//ok
`include "defines.v"
module IFU(
    //from if 
    input wire rst,
    input wire[`InstBus] inst_i,
    input wire[`InstAddrBus] InstAddr_i,
    //from id
    input wire jalr_predicition_i,
    input wire[`RegBus] rdata_i,
    //to pc 
    output reg[`InstAddrBus] predict_pc_o,
    output reg jump_prediction_o,
    //to hold 
    output reg prediciton_hold_o
    

    );
    wire[6:0] opcode = inst_i[6:0];
    wire[4:0] rs1 = inst_i[19:15];
    wire[`InstAddrBus] predict_pc;
//predic
    always @ (*)
        begin
            if (rst == `RstEnable)
                begin
                    predict_pc_o = `ZeroWord;
                    jump_prediction_o =  `PredictionDisable;
                    prediciton_hold_o = `HoldDisable;
                end 
            else
                begin
                    if (jalr_predicition_i == `PredictionEnable)
                        begin
                            predict_pc_o = (rdata_i + {{20{inst_i[31]}}, inst_i[31:20]}) & (32'hffff_fffc);
                            jump_prediction_o =  `PredictionEnable;
                            prediciton_hold_o = `HoldDisable;
                        end
                    else
                        begin
                            case(opcode)
                                `INST_JAL:
                                    begin
                                        predict_pc_o = InstAddr_i + {{12{inst_i[31]}}, inst_i[19:12], inst_i[20], inst_i[30:21], 1'b0};
                                        jump_prediction_o =  `PredictionEnable;
                                        prediciton_hold_o = `HoldDisable;
                                    end
                                `INST_JALR:
                                    begin
                                        if (rs1 == 5'b0)
                                            begin
                                                predict_pc_o = ({{20{inst_i[31]}}, inst_i[31:20]}) & (32'hffff_fffc);
                                                jump_prediction_o =  `PredictionEnable;
                                                prediciton_hold_o = `HoldDisable;
                                            end
                                        else
                                            begin
                                                predict_pc_o = `ZeroWord;
                                                jump_prediction_o =  `PredictionDisable;
                                                prediciton_hold_o = `HoldEnable;
                                            end
                                        
                                    end
                                `INST_TYPE_B:
                                    begin
                                        //BTFN(Back Taken, Forward Not Taken)
                                        if (inst_i[31] == 1'b1)
                                            begin
                                                predict_pc_o = InstAddr_i + {{20{inst_i[31]}}, inst_i[7], inst_i[30:25], inst_i[11:8], 1'b0};
                                                jump_prediction_o =  `PredictionEnable;
                                                prediciton_hold_o = `HoldDisable;
                                            end
                                        else
                                            begin
                                                predict_pc_o = `ZeroWord;
                                                jump_prediction_o =  `PredictionDisable;
                                                prediciton_hold_o = `HoldDisable;
                                            end
                                    end
                                default:
                                    begin
                                        predict_pc_o = `ZeroWord;
                                        jump_prediction_o =  `PredictionDisable;
                                        prediciton_hold_o = `HoldDisable;
                                    end


                            endcase
                        end
                end
        end
    
endmodule
